%% Author: maciek
%% Created: 13-04-2011
%% Description: TODO: Add description to iax2_parser
-module(iax2_parser).
-compile(export_all).
-include("iax2_common.hrl").
%%
%% Exported Functions
%%
-export([]).

%%
%% API Functions
%%
%%%VOICE FULL FRAME

decode_iax2_frame(<<1:1,
					Src_call_number:15,
					R:1,
					Dst_call_number:15,
					Timestamp:32,
					OSeqno:8,
					ISeqno:8,
					2:8,%Frame_type:8, Voice Full Frame
					C:1,
					Subclass:7,Data/binary>>) -> 
	
	Rec=#fullframe{srccallnumber=Src_call_number,
			   r=R,
			   dstcallnumber=Dst_call_number,
			   timestamp=Timestamp,
			   oseqno=OSeqno,
					iseqno=ISeqno,
					frametype=voice,
					c=C,
					subclass=frame_subclass_to_atom(voice,Subclass),
					data=Data},
	%io:format("Full Frame ~n~p~n", [Rec]).
	%%decode_ie_content(Data).
	Rec;
decode_iax2_frame(<<1:1,
					Src_call_number:15,
					R:1,
					Dst_call_number:15,
					Timestamp:32,
					OSeqno:8,
					ISeqno:8,
					Frame_type:8,
					C:1,
					Subclass:7,Data/binary>>) -> 
	FT = frametype_to_atom(Frame_type),
	Rec=#fullframe{srccallnumber=Src_call_number,
			   r=R,
			   dstcallnumber=Dst_call_number,
			   timestamp=Timestamp,
			   oseqno=OSeqno,
					iseqno=ISeqno,
					frametype=FT,
					c=C,
					subclass=frame_subclass_to_atom(FT,Subclass),
					data=decode_ie_content(Data)},
	%io:format("Full Frame ~n~p~n", [Rec]).
	%%decode_ie_content(Data).
	Rec.




decode_ie_content(<<>>) -> [];
decode_ie_content(Bin) ->
	[IE1,Rest1]=decode_ie(Bin),	
	[IE1|decode_ie_content(Rest1)].


frametype_to_atom(FT) ->
	element(1,lists:keyfind(FT,2,?FRAME_TYPE_MAP)).

frame_subclass_to_atom(iax,Subclass) ->
	element(1,lists:keyfind(Subclass,2,?IAX_SUBCLASSES_MAP));
frame_subclass_to_atom(control,Subclass) ->
	element(1,lists:keyfind(Subclass,2,?CONTROL_SUBCLASSES_MAP));	
frame_subclass_to_atom(voice,Subclass) ->
	undefined_voice_frame.
			   

%%
%% Local Functions
%%



decode_ie(<<16#0b:8,Len:8,Data/binary>>) ->
	Ie_content = binary:part(Data, 0, Len),
	Rest = binary:part(Data, Len,byte_size(Data)-Len),
	R=#ie_protocol_ver{version=binary:decode_unsigned(Ie_content)},
	%%io:format("R = ~p~n", [R]),
	[R,Rest];



decode_ie(<<16#01:8,Len:8,Data/binary>>) ->
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_called_number{called_number=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#02:8,Len:8,Data/binary>>) ->
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_calling_number{calling_number=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#03:8,Len:8,Data/binary>>) ->
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_calling_ani{calling_ani=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#04:8,Len:8,Data/binary>>) ->
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_calling_name{calling_name=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#05:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_called_context{called_context=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#06:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_username{username=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#07:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_password{password=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];


%%TODOOOOO
decode_ie(<<16#08:8,4:8,Caps:32,Data/binary>>) -> 
R=#ie_capability{capability=capabilites_to_list(Caps,?FORMAT_LIST)},
%%io:format("R = ~p~n", [R]),
[R,Data];
%%TODO
decode_ie(<<16#09:8,4:8,Format:32,Data/binary>>) -> 
R=#ie_format{format=format_to_atom(Format)},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#0a:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_language{language=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];



decode_ie(<<16#0c:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_adsicpe{adsicpe=(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#0d:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_dnid{dnid=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

%%%AUTHMETHODS
decode_ie(<<16#0e:8,16#2:8,16#0001:16,Data/binary>>) -> 
R=#ie_authmethods{authmethods='auth_method_reserved'},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#0e:8,16#2:8,16#0002:16,Data/binary>>) -> 
R=#ie_authmethods{authmethods='auth_method_md5'},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#0e:8,16#2:8,16#0004:16,Data/binary>>) -> 
R=#ie_authmethods{authmethods='auth_method_rsa'},
%%io:format("R = ~p~n", [R]),
[R,Data];


decode_ie(<<16#0e:8,16#2:8,Method:16,Data/binary>>) -> 
R=#ie_authmethods{authmethods=Method},
%%io:format("R = ~p~n", [R]),
[R,Data];






decode_ie(<<16#0f:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_challenge{challenge=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#10:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_md5_result{md5_result=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#11:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_rsa_result{rsa_result=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];


%%%Warn only IPv4 supported
decode_ie(<<16#12:8,16#10:8,16#0200:16,16#11d9,IpAddr:32,_Padding:64,Data/binary>>) -> 
R=#ie_apparent_addr{apparent_addr={ipv4,IpAddr}},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#13:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_refresh{refresh=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#14:8,2:8,Mask:16,Data/binary>>) -> 
R=#ie_dpstatus{dpstatus=Mask},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#15:8,2:8,Callno:16,Data/binary>>) -> 
R=#ie_callno{callno=Callno},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#16:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_cause{cause=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#17:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_iax_unknown{iax_unknown=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#18:8,2:8,OldMsgs:8,NewMsgs:8,Data/binary>>) -> 
R=#ie_msgcount{newmsgs=NewMsgs,oldmsgs=OldMsgs},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#19:8,0:8,Data/binary>>) -> 
R=#ie_autoanswer{},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#1a:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_musiconhold{musiconhold=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#1b:8,4:8,Transferid:32,Data/binary>>) -> 
R=#ie_transferid{transferid=Transferid},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#1c:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_rdnis{rdnis=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#1d:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_reserved{reserved=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#1e:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_reserved{reserved=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#1f:8,4:8,Year:7,Month:4,Day:5,Hours:5,Minutes:6,Seconds:5,Data/binary>>) -> 
R=#ie_datetime{year=Year,month=Month,day=Day,hours=Hours,minutes=Minutes,seconds=Seconds},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#20:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_reserved{reserved=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#21:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_reserved{reserved=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#22:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_reserved{reserved=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#23:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_reserved{reserved=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#24:8,Len:8,Data/binary>>) -> 
%%io:format("24th ie len = ~p~nData = ~w~n", [Len,Data]),
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_reserved{reserved=binary:bin_to_list(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#25:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_reserved{reserved=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#26:8,1:8,CallingPres:8,Data/binary>>) -> 
R=#ie_callingpres{callingpres=CallingPres},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#27:8,1:8,Callington:8,Data/binary>>) -> 
R=#ie_callington{callington=Callington},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#28:8,2:8,_:1,TON:3,Plan:4,NetId:8,Data/binary>>) -> 
R=#ie_callingtns{ton=TON,plan=Plan,netid=NetId},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#29:8,2:8,SamplingRate:16,Data/binary>>) -> 
R=#ie_samplingrate{samplingrate=SamplingRate},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#2a:8,1:8,CC:8,Data/binary>>) -> 
R=#ie_causecode{causecode=CC},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#2b:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_encryption{encryption=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#2c:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_enckey{enckey=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];
%%TODO
decode_ie(<<16#2d:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_codec_prefs{codec_prefs=(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<16#2e:8,4:8,RR:32,Data/binary>>) -> 
R=#ie_rr_jitter{rr_jitter=RR},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#2f:8,4:8,LossPercent:8,LossCount:24,Data/binary>>) -> 
R=#ie_rr_loss{rr_loss_percent=LossPercent,rr_loss_count=LossCount},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#30:8,4:8,FramesReceived:32,Data/binary>>) -> 
R=#ie_rr_pkts{rr_pkts=FramesReceived},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#31:8,2:8,Delay:16,Data/binary>>) -> 
R=#ie_rr_delay{rr_delay=Delay},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#32:8,4:8,FramesDropped:32,Data/binary>>) -> 
R=#ie_rr_dropped{rr_dropped=FramesDropped},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#33:8,4:8,FramesOOO:32,Data/binary>>) -> 
R=#ie_rr_ooo{rr_ooo=FramesOOO},
%%io:format("R = ~p~n", [R]),
[R,Data];

decode_ie(<<16#34:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#ie_osptoken{osptoken=Ie_content},
%%io:format("R = ~p~n", [R]),
[R,Rest];

decode_ie(<<_:8,0:8,Data/binary>>) -> 
R=#unknown{},
%%io:format("Zero size R = ~p~nNext ~w~n", [R,Data]),
[R,Data];

decode_ie(<<_:8,Len:8,Data/binary>>) -> 
Ie_content = binary:part(Data, 0, Len),
Rest = binary:part(Data, Len,byte_size(Data)-Len),
R=#unknown{content=binary:decode_unsigned(Ie_content)},
%%io:format("R = ~p~n", [R]),
[R,Rest].



format_to_atom(FormatNo) -> element(2,lists:keyfind(FormatNo,1,?FORMAT_MAP)).


capabilites_to_list(Mask,FormatList) when length(FormatList) > 1->
	[H|T] = FormatList,
	if 
		Mask band H =:= H ->
			[format_to_atom(H)|capabilites_to_list(Mask,T)];
		true ->
			capabilites_to_list(Mask,T)
	end;
capabilites_to_list(Mask,H) when length(H) == 1 ->
	
	if 
		Mask band H =:= H ->
			format_to_atom(H);
		true ->
			[]
		end.
